/* eslint-disable max-lines-per-function */
import {memo} from 'react';
import {useCreation, usePersistFn} from 'ahooks';
import {useRequest, history} from 'umi';
import {Input, DatePicker, Radio, Checkbox, message, Select, Form, Button} from 'antd';
// import {PageContainer} from '@ant-design/pro-layout';
import PageHeader from '@/components/PageHeader';
// 封装一个通用表单组件，可通过传入配置生成表单
import DefaultForm from '@/components/DefaultForm';
// 自定义上传组件，表单中经常会包裹自定义组件
import Annex from './Annex';
import styles from './index.less';
import {saveItem} from './service';
// 配置文件中获取公共表单布局配置
import {layout, facultyList, activityTypeList, roleList} from './config';


const {RangePicker} = DatePicker;
const {TextArea} = Input;
const {Option} = Select;

// 项目中多次使用的常量及配置要提取到公共文件，单个组件使用可写在该组件上方
// 语义化
const DEFAULT_COURSE_NAME = 'course';
const DEFAULT_CLAZZ_NAME = 'clazz';
const DEFAULT_SUBCLAZZ_NAME = 'subclazz';
const ACTIVITY_NAME_MAX_LEN = 30;
const ACTIVITY_INFO_ROWS = 8;
const UPLOAD_ANNEX_ACTION = 'https://api.baijia.com/mock/2545/api/crud/upload';
const DEBOUNCE_INTERVAL = 500;
const FOOTER_WRAPPER_COL = {
    span: 10,
    offset: 10
};

// 使用配置替代判断
const activityRangeConfig = {
    [DEFAULT_COURSE_NAME]: '第一课',
    [DEFAULT_CLAZZ_NAME]: '第一班',
    [DEFAULT_SUBCLAZZ_NAME]: '第一辅导班'
};

const rangeList = [
    {key: 'course', value: '课程'},
    {key: 'clazz', value: '班级'},
    {key: 'subclazz', value: '辅导班'},
];

const FormItem = Form.Item;
const Edit = () => {
    const [form] = Form.useForm();
    // 使用usePersistFn缓存函数引用，防止子组件产生额外更新
    const handleCancel = usePersistFn(() => {
        // 跳转列表页
        history.push('/crud');
    });
    // 使用useRequest进行接口请求
    const {loading: saveLoading, run: onFinish} = useRequest(saveItem, {
        manual: true,
        // 防抖处理
        debounceInterval: DEBOUNCE_INTERVAL,
        // 成功回调
        onSuccess() {
            message.success('保存成功!');
            handleCancel();
        }
    }) || {};
    // 使用usePersistFn缓存函数引用
    const onRangeChange = usePersistFn((value, renderProps) => {
        const {form} = renderProps;
        // 根据内容进行表单值设置
        form.setFieldsValue({present: activityRangeConfig?.[value]});
    });
    // 需多处获取Radio Group 进行函数提取
    const getRadioGroup = list => (
        <Radio.Group>
            {list.map(item => (
                <Radio
                    key={item?.key}
                    value={item?.key}
                >
                    {item?.value}
                </Radio>
            ))}
        </Radio.Group>
    );
    // 使用useCreation缓存计算后的dom
    const cachedFacultyRadioGroup = useCreation(() => getRadioGroup(facultyList), [facultyList]);
    const cachedCourseTypeRadioGroup = useCreation(() => getRadioGroup(activityTypeList), [activityTypeList]);
    const cachedRoleCheckboxGroup = useCreation(() => (
        <Checkbox.Group >
            {roleList.map(item => {
                // 不解构也可以，注意做好兼容
                const {key, value} = item || {};
                return (
                    <Checkbox
                        key={key}
                        value={key}
                    >
                        {value}
                    </Checkbox>
                );
            })}
        </Checkbox.Group>
    ), [roleList]);
    const cachedRangeSelectOption = useCreation(() => rangeList.map(item => {
        const {key, value} = item || {};
        return (
            <Option
                key={key}
                value={key}
            >
                {value}
            </Option>
        );
    }), [roleList]);
    const validateActivityName = (rule, value, callback) => {
        // 活动名称校验
        if (!value) {
            callback('活动名称不能为空');
        }
        if (value?.includes('?')) {
            callback('活动名称不可以带?哦');
        }
        callback();
    };
    // 使用useCreation创建常量，类似于useRef（好处 1 取值更方便 2 避免性能隐患）
    const formItems = useCreation(() => [
        {
            label: '活动名称',
            key: 'promotionActivityName',
            name: 'promotionActivityName',
            rules: [{required: true, validator: validateActivityName}],
            render: () => (
                <Input
                    placeholder="请输入活动名称"
                    maxLength={ACTIVITY_NAME_MAX_LEN}
                />
            )
        },
        {
            label: '商品类型',
            key: 'productType',
            name: 'productType',
            rules: [{required: true, message: '商品类型不能为空'}],
            render: () => cachedCourseTypeRadioGroup
        },
        {
            label: '活动学部',
            key: 'phaseType',
            name: 'phaseType',
            rules: [{required: true, message: '活动学部不能为空'}],
            render: () => cachedFacultyRadioGroup
        },
        {
            label: '活动业务线',
            key: 'businessLineTypes',
            name: 'businessLineTypes',
            rules: [{required: true, message: '活动业务线不能为空'}],
            render: () => cachedRoleCheckboxGroup
        },
        {
            label: '活动时间',
            key: 'activityTime',
            name: 'activityTime',
            rules: [{type: 'array', required: true, message: '请选择活动时间'}],
            render: () => (
                <RangePicker
                    showTime
                />
            )
        },
        {
            label: '活动说明',
            // 表单字段嵌套结构，name可以直接使用数组
            name: ['info', 'description'],
            render: () => (
                <TextArea
                    placeholder="请输入活动说明"
                    rows={ACTIVITY_INFO_ROWS}
                />
            )
        },
        {
            label: '赠品信息',
            // 表单字段嵌套结构name可以直接使用数组
            name: ['info', 'present'],
            render: () => (
                <Input
                    placeholder="请输入赠品信息"
                />
            )
        },
        {
            label: '活动范围',
            name: 'range',
            render: renderProps => (
                <Select
                    placeholder="请选择活动范围"
                    onChange={value => onRangeChange(value, renderProps)}
                    allowClear
                >
                    {cachedRangeSelectOption}
                </Select>
            )
        },
        {
            key: 'courseName',
            // 该表单字段更改则进行更新
            shouldUpdate: (prevValues, currentValues) => prevValues.range !== currentValues.range,
            // 去掉FormItem默认样式
            noStyle: true,
            render: () => ({getFieldValue}) => (getFieldValue('range') === 'course' ? (
                // 根据表单字段值控制其他表单字段显隐
                <FormItem
                    name="courseName"
                    label="课程名称"
                    rules={[{required: true, message: '请输入课程名称'}]}
                >
                    <Input />
                </FormItem>
            ) : null)
        },
        {
            label: '活动审批结果',
            name: 'file',
            render: () => (
                <Annex
                    action={UPLOAD_ANNEX_ACTION}
                />
            )
        },
        {
            key: 'footer',
            wrapperCol: FOOTER_WRAPPER_COL,
            render: () => (
                <>
                    {/* 此处必须添加loading，保存接口loading */}
                    <Button loading={saveLoading} type="primary" htmlType="submit">保存</Button>
                    <Button loading={saveLoading} onClick={handleCancel} className={styles.ml10}>取消</Button>
                </>
            )
        }
    ], []);

    const handleFinish = usePersistFn((params = {}) => {
        const payload = {...params};
        // 注意兼容处理
        const {activityTime} = payload || {};
        // 时间类型单独处理
        const [begin, end] = activityTime || [];
        if (payload?.activityTime) {
            // 转换时间戳，注意容错处理
            payload.activityTime = [begin?.valueOf(), end?.valueOf()];
        }
        onFinish(payload);
    });

    const onFieldsChange = usePersistFn((changedFields, allFields) => {
        // 表单值变化或触发验证时触发，能够获取更多表单元素属性
        console.log('字段更新了，可以做自己的逻辑处理', changedFields, allFields);
    });

    const onValuesChange = usePersistFn((changedFields, allFields) => {
        // 表单值变化会触发，只能获取表单字段名和值
        console.log('字段值更新了，可以做自己的逻辑处理', changedFields, allFields);
        const {businessLineTypes} = changedFields || {};
        if (businessLineTypes?.length > 0) {
            // 判断某个表单项变化触发校验其他表单项
            form.validateFields(['promotionActivityName']);
        }
    });

    // PageContainer属性请查阅https://procomponents.ant.design/components/layout#pagecontainer
    return (
        <PageHeader>
            <div className={styles.card}>
                <DefaultForm
                    form={form}
                    // @ts-ignore
                    formItems={formItems}
                    onFinish={handleFinish}
                    layout={layout}
                    onFieldsChange={onFieldsChange}
                    onValuesChange={onValuesChange}
                />
            </div>
        </PageHeader>
    );
};

// 组件使用memo包裹，默认进行浅比较，减少组件渲染次数
export default memo(Edit);
